package com.epoch.base.export;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

public class JsonExporter extends AbstractTextExporter {
    private static final String JSON_BRACE_OPEN = "{";
    private static final String JSON_BRACE_CLOSE = "}";
    private static final String JSON_BRACKET_OPEN = "[";
    private static final String JSON_BRACKET_CLOSE = "]";
    private static final String JSON_QUOT = "\"";
    private static final String JSON_COLON = ":";
    private static final String JSON_COMMA = ",";
    private static final String JSON_ESC = "\\";

    @Override
    protected void doTextExport(BufferedWriter writer, Collection<?> data, List<HeadMeta> headMetas,
        Map<Integer, IExportConvertor> indexCvtorMap, Map<String, IExportConvertor> fieldCvtorMap,
        Map<String, Object> params) throws IOException, ExportException {
        if (CollectionUtils.isNotEmpty(headMetas)) {
            writer.write(JSON_BRACE_OPEN);
            writer.write(this.buildJsonStrField("header"));
            writer.write(JSON_COLON);
            writer.write(JSON_BRACKET_OPEN);
            writer.write(JSON_BRACKET_OPEN);
            int c = 0;
            int cols = headMetas.size();
            for (; c < cols; c++) {
                if (c > 0) {
                    writer.write(JSON_COMMA);
                }
                HeadMeta meta = headMetas.get(c);
                String title = meta.getTitle();
                writer.write(this.buildJsonStrField(title));
            }
            writer.write(JSON_BRACKET_CLOSE);
            writer.write(JSON_BRACKET_CLOSE);
            if (data != null) {
                writer.write(JSON_COMMA);
                writer.write(this.buildJsonStrField("data"));
                writer.write(JSON_COLON);
                writer.write(JSON_BRACKET_OPEN);
                int r = 0;
                for (Object rowData : data) {
                    if (r > 0) {
                        writer.write(JSON_COMMA);
                    }
                    writer.write(JSON_BRACE_OPEN);
                    if (rowData != null) {
                        for (c = 0; c < cols; c++) {
                            if (c > 0) {
                                writer.write(JSON_COMMA);
                            }
                            HeadMeta meta = headMetas.get(c);
                            String field = meta.getField();
                            String title = meta.getTitle();
                            Object val = this.obtainFieldVal(rowData, indexCvtorMap, fieldCvtorMap, field, r, c);
                            writer.write(this.buildJsonStrField(title));
                            writer.write(JSON_COLON);
                            String valStr = this.buildJsonStrField(null);
                            if (val instanceof Boolean || val instanceof Number) {
                                valStr = val.toString();
                            } else if (val instanceof Date) {
                                valStr = ExportConstant.DATETIME_FORMAT.format((Date)val);
                            } else if (val != null) {
                                valStr = this.buildJsonStrField(val.toString());
                            }
                            writer.write(valStr);
                        }
                    }
                    writer.write(JSON_BRACE_CLOSE);
                    r++;
                }
                writer.write(JSON_BRACKET_CLOSE);
            }
            writer.write(JSON_BRACE_CLOSE);
        }
    }

    @Override
    public String getFileNameExt() {
        return ".json";
    }

    private String buildJsonStrField(String str) {
        String result = StringUtils.trimToEmpty(str);
        result.replace(JSON_ESC, JSON_ESC + JSON_ESC);
        result.replace(JSON_QUOT, JSON_ESC + JSON_QUOT);
        result = JSON_QUOT + result + JSON_QUOT;
        return result;
    }
}
